package com.ws.framework.shiro;

import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.ws.framework.dao.RoleDao;
import com.ws.framework.dao.UserDao;
import com.ws.framework.model.Permission;
import com.ws.framework.model.Role;
import com.ws.framework.model.User;

/**
 * 
 * <p>
 * </p>
 *
 * @author WSH
 */
public class MyShiroRealm extends AuthorizingRealm{

    private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

    @Autowired
    UserDao userDao; 
    @Autowired
    RoleDao roleDao;

    /**
     * 权限认证，为当前登录的Subject授予角色和权限 
     * @see 经测试：本例中该方法的调用时机为需授权资源被访问时 
     * @see 经测试：并且每次访问需授权资源时都会执行该方法中的逻辑，这表明本例中默认并未启用AuthorizationCache 
     * @see 经测试：如果连续访问同一个URL（比如刷新），该方法不会被重复调用，Shiro有一个时间间隔（也就是cache时间，在ehcache-shiro.xml中配置），超过这个时间间隔再刷新页面，该方法会被执行
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("##################执行Shiro权限认证##################");
        User user = (User)super.getAvailablePrincipal(principalCollection); 
        if(!Objects.isNull(user)){
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            List<Role> roles = userDao.selectRolesByUserId(user.getId());
            Set<String> roleNames = Sets.newHashSet(Lists.transform(roles, new Function<Role, String>() {
				@Override
				public String apply(Role input) {
					return input.getRoleName();
				}
			}));
            //添加角色
            info.setRoles(roleNames);
            Set<String> permissionNames = Sets.newHashSet();
            for (Role role : roles) {
            	permissionNames.addAll(Lists.transform(roleDao.selectPermissionByRoleId(role.getId()), new Function<Permission, String>() {
    				@Override
    				public String apply(Permission input) {
    					return input.getPermissionName();
    				}
    			}));
            }
            //添加权限
            info.addStringPermissions(permissionNames);
            //info.addStringPermissions(Lists.newArrayList("user:admin"));
            return info;
        }
        // 返回null的话，就会导致任何用户访问被拦截的请求时，都会自动跳转到unauthorizedUrl指定的地址
        return null;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
        logger.info("验证当前Subject时获取到token为：" + token); 
        User user = userDao.selectByName(token.getUsername());
        if(!Objects.isNull(user)){
            return new SimpleAuthenticationInfo(user, user.getPwd(), getName());
        }
        return null;
    }
}